home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
ASME's Mechanical Engine…ing Toolkit 1997 December
/
ASME's Mechanical Engineering Toolkit 1997 December.iso
/
win_eng
/
atre27.exe
/
ATREE_27
/
INCLUDE
/
ATREE.C
next >
Wrap
C/C++ Source or Header
|
1992-08-01
|
74KB
|
2,184 lines
/*****************************************************************************
**** ****
**** atree.c for Windows ****
**** ****
**** atree release 2.7 ****
**** Adaptive Logic Network (ALN) simulation library. ****
**** Copyright (C) A. Dwelly, R. Manderscheid, M. Thomas, W.W. Armstrong ****
**** 1991, 1992 ****
**** ****
**** License: ****
**** A royalty-free license is granted for the use of this software for ****
**** NON_COMMERCIAL PURPOSES ONLY. The software may be copied and/or ****
**** modified provided this notice appears in its entirety and unchanged ****
**** in all derived source programs. Persons modifying the code are ****
**** requested to state the date, the changes made and who made them ****
**** in the modification history. ****
**** ****
**** Patent License: ****
**** The use of a digital circuit which transmits a signal indicating ****
**** heuristic responsibility is protected by U. S. Patent 3,934,231 ****
**** and others assigned to Dendronic Decisions Limited of Edmonton, ****
**** W. W. Armstrong, President. A royalty-free license is granted ****
**** by the company to use this patent for NON_COMMERCIAL PURPOSES ONLY ****
**** to adapt logic trees using this program and its modifications. ****
**** ****
**** Limited Warranty: ****
**** This software is provided "as is" without warranty of any kind, ****
**** either expressed or implied, including, but not limited to, the ****
**** implied warrantees of merchantability and fitness for a particular ****
**** purpose. The entire risk as to the quality and performance of the ****
**** program is with the user. Neither the authors, nor the ****
**** University of Alberta, its officers, agents, servants or employees ****
**** shall be liable or responsible in any way for any damage to ****
**** property or direct personal or consequential injury of any nature ****
**** whatsoever that may be suffered or sustained by any licensee, user ****
**** or any other party as a consequence of the use or disposition of ****
**** this software. ****
**** ****
**** Modification history: ****
**** ****
**** 90.05.09 Initial implementation, A.Dwelly ****
**** 91.07.15 Release 2, Rolf Manderscheid ****
**** Thanks to Allen Supynuk for turning my compression ****
**** function into something readable. ****
**** 91.10.30 0.0 and 1.0 replaced by code -> low and code -> high in ****
**** atree_read_code to correct bug found by Monroe Thomas ****
**** 92.27.02 Release 2.5, Monroe Thomas ****
**** 92.03.07 Release 2.6, Monroe Thomas ****
**** 92.01.08 Release 2.7, Monroe Thomas ****
**** ****
*****************************************************************************/
/*****************************************************************************
**** ****
**** Include Files ****
**** ****
*****************************************************************************/
#include <windows.h>
#include <time.h>
#ifndef __ATREE_H
#include "atree.h"
#endif
extern int errno;
/*****************************************************************************
**** ****
**** Constants ****
**** ****
*****************************************************************************/
/* Node and leaf types */
#define AND 0
#define RIGHT 1
#define LEFT 2
#define OR 3
#define LEAF 4
#define LEFT_CHILD 0
#define RIGHT_CHILD 1
#define FALSE 0 /* As usual */
#define TRUE 1
#define UNEVALUATED 2 /* We complete the lattice of boolean functions */
#define ATREE_ERROR 3
/* Number of retries before an error in atree_rand_walk */
#define MAX_RETRY 50
/* Number of nodes/leaves to allocate in each call to malloc in get_node() */
#define NEWMALLOC 1024
/* Initialisation values */
#define MAXSET 63
#define ABOVEMID 32
#define BELOWMID 31
#define MINSET 0
#define STACKSIZE 100 /* stack used in load_tree */
#define LEAF_TOKEN 256
#define CODING_HEADER_FORMAT "vectors=%i, width=%i, range=%f,%f\n"
#define CODING_HEADER_ITEMS 4
/*
* Macros
*/
/* This keeps lint quiet */
#define Printf (void) printf
/* Public and private procedures */
#define public
#define private static
/* Infinite loops - for EVER */
#define EVER (;;)
/* Printing out the boolean lattice */
#define PRINTBOOL(b) if (b == TRUE) {Printf("1");} else if (b == FALSE)\
{Printf("0");} else if (b == UNEVALUATED) {Printf("U");} else \
if (b == ATREE_ERROR) {Printf("E");} else {Printf("?");}
/* Verbosity */
#define VERBOSE(level,s) if (verbosity >= level) {s ;}
/*
* Types
*/
typedef struct token_struct
{
int token;
int bit_no;
int complemented;
} token_t; // struct is 6 bytes long
/*
* Preliminary Private Procedure Declarations
*/
private LPATREE NEAR PASCAL get_node(int);
private void NEAR PASCAL reclaim_node(LPATREE);
private LPATREE NEAR PASCAL build_tree(LPINT, BOOL far *,int,int);
private void NEAR PASCAL print_tree(LPATREE, FILE *, int, int);
private BOOL NEAR PASCAL train(LPATREE, LPBIT_VEC, BOOL);
private void NEAR PASCAL adapt(LPATREE, LPBIT_VEC, BOOL);
private int NEAR PASCAL node_function(LPATREE);
private void NEAR PASCAL compress_tree(LPATREE,LPFAST_TREE,LPFAST_TREE,LPFAST_TREE,LPINT);
private int NEAR PASCAL count_leaves(LPATREE, int);
private int NEAR PASCAL store_tree(LPATREE, FILE *);
private int NEAR PASCAL get_token(FILE *, token_t far *);
BOOL atree_quit_flag;
HWND hStatusWnd;
#pragma argsused
long FAR PASCAL StatusDlgProc(HWND hwnd, WORD message, WORD wParam, LONG lParam)
{
if ((message == WM_COMMAND) && (wParam == IDCANCEL))
{
atree_quit_flag = TRUE;
return(TRUE);
}
return(FALSE);
}
/*****************************************************************************
*****************************************************************************
**** ****
**** Public Routines ****
**** ****
*****************************************************************************
*****************************************************************************/
/*****************************************************************************
**** ****
**** void FAR PASCAL Windows_Interrupt(cElapsed) ****
**** ****
**** DWORD cElapsed ****
**** ****
**** Synopsis: ****
**** ****
**** Allows Windows to access other applications that may be running ****
**** A call to PeekMessage accomplishes this, and we process all calling ****
**** window messages. Will only call PeekMessage if _cElapsed_ time ****
**** has passed since the last call to Windows_Interrupt. ****
**** ****
*****************************************************************************/
public void FAR PASCAL
Windows_Interrupt(cElapsed)
DWORD cElapsed;
{
static DWORD cTick = 0; /* number of ticks since first called */
MSG msg; /* Windows message structure */
if ((GetTickCount() - cTick) > cElapsed)
{
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
cTick = GetTickCount();
}
}
/*****************************************************************************
**** ****
**** void atree_init(hInstance, hWindow) ****
**** ****
**** HANDLE hInstance; ****
**** ****
**** Synopsis: ****
**** ****
**** Initialises various global variables, and makes an initial call to ****
**** the random number seed routine. ****
*****************************************************************************/
public void FAR PASCAL
atree_init(hInstance, hWindow)
HANDLE hInstance;
HWND hWindow;
{
DWORD c;
#pragma warn -nod
randomize();
#pragma warn .nod
c = GetTickCount();
(void) srand((int) c);
c = GetWinFlags();
if (!(c & WF_PMODE))
{
MessageBox(hWindow, "Atree software cannot run\nin Windows Real Mode!",
"Not in Protected Mode!", MB_OK | MB_ICONSTOP);
exit(0);
}
hStatusWnd = CreateDialog(hInstance, "atreeStatus", hWindow,
MakeProcInstance((FARPROC)StatusDlgProc, hInstance));
atree_quit_flag = FALSE;
return;
}
/*****************************************************************************
**** ****
**** void atree_quit() ****
**** ****
**** sets the quit flag for use by other atree routines when an exit ****
**** is desired ****
*****************************************************************************/
void FAR PASCAL
atree_quit(void)
{
atree_quit_flag = TRUE;
if (IsWindow(hStatusWnd))
{
DestroyWindow(hStatusWnd);
}
}
/*****************************************************************************
**** ****
**** LPBIT_VEC atree_rand_walk(num,width,p) ****
**** ****
**** int num; ****
**** int width; ****
**** int p; ****
**** ****
**** Synopsis: ****
**** ****
**** Creates an array of _num_ binary vectors, of _width_ bits where ****
**** each is _p_ bits away from its neighbours in Hamming space. Each ****
**** vector is unique. ****
**** This routine returns NULL if it's unable to find enough vectors. ****
*****************************************************************************/
public LPBIT_VEC FAR PASCAL
atree_rand_walk(num,width,p)
int num;
int width;
int p;
{
/*
* An initial vector is produced with random bits, and each subsequent
* vector in the random walk just has _p_ bits flipped. In order to
* guarantee that each vector is unique, it is checked against
* a chained list of vectors of the same bit sum. If it is not already
* in the chain it is appended to the end, or else the vector is discarded
* and the process repeats itself.
*/
LPBIT_VEC walk; /* An array of bit vectors */
LPBIT_VEC pckd_vec; /* The packed unique ? vector */
BOOL unique; /* Uniqueness flag set during testing */
LPINT bit_sum_chain; /* Pointers to vectors of equivalent bit sums */
LPINT next_vec; /* Chain array */
LPSTR unpckd_vec; /* An unpacked vector */
LPSTR this_vec; /* An unpacked vector */
LPSTR mark_vec; /* TRUE where a bit has been flipped */
int i;
int j;
int old_bit_sum; /* Last number of TRUE bits in vector */
int bit_sum; /* Current number of TRUE bits in vector */
int retrys; /* Number of attempts to find a unique vec */
int victim; /* The bit just twiddled */
int current_vec; /* Part of the chain */
assert(num > 0);
assert(width > 0);
assert(p > 0 && p <= width);
/* Assign space in memory */
walk = (LPBIT_VEC ) farmalloc((unsigned) num * sizeof(bit_vec));
MEMCHECK(walk);
bit_sum_chain = (LPINT) farmalloc((unsigned) (width+1) * sizeof(int));
MEMCHECK(bit_sum_chain);
next_vec = (LPINT) farmalloc((unsigned) num * sizeof(int));
MEMCHECK(next_vec);
unpckd_vec = (LPSTR) farmalloc((unsigned) width * sizeof(char));
MEMCHECK(unpckd_vec);
this_vec = (LPSTR) farmalloc((unsigned) width * sizeof(char));
MEMCHECK(this_vec);
mark_vec = (LPSTR) farmalloc((unsigned) width * sizeof(char));
MEMCHECK(mark_vec);
/* Clear bit_sum_chain */
for (i = 0; i <= width; i++)
{
bit_sum_chain[i] = -1;
}
/* Clear next_vec */
for (i = 0; i < num; i++)
{
next_vec[i] = -1;
}
/* Create initial vector and bit sum */
old_bit_sum = 0;
for (i = 0; i < width; i++)
{
// turn off compiler possibly incorrect assignment warning
#pragma warn -pia
if (unpckd_vec[i] = RANDOM(2))
{
old_bit_sum++;
}
// restore warning state
#pragma warn .pia
}
walk[0] = *(bv_pack(unpckd_vec,width));
bit_sum_chain[old_bit_sum] = 0;
/* Random walk */
for (i = 1; i < num; i++)
{
retrys = 0;
unique = FALSE;
while ((!unique) && (retrys < MAX_RETRY))
{
retrys++;
/* Make a new vector */
bit_sum = old_bit_sum;
for (j = 0; j < width; j++)
{
this_vec[j] = unpckd_vec[j];
mark_vec[j] = FALSE;
}
for (j = 0; j < p; j++)
{
do
{
victim = RANDOM(width);
}
while (mark_vec[victim]);
mark_vec[victim] = TRUE;
this_vec[victim] = !this_vec[victim];
if (this_vec[victim] == FALSE)
{
bit_sum--;
}
else
{
bit_sum++;
}
}
pckd_vec = bv_pack(this_vec,width);
/* Compare it with the existing ones of equal bit length */
if (bit_sum_chain[bit_sum] == -1)
{
/* There are no other vectors with this bit sum, so */
unique = TRUE;
walk[i] = *pckd_vec;
bit_sum_chain[bit_sum] = i;
next_vec[i] = -1;
}
else
{
current_vec = bit_sum_chain[bit_sum];
for EVER /* We break out of here inside the loop */
{
if (bv_equal(&(walk[current_vec]),pckd_vec))
{
/* This vector already exists, unique = FALSE; */
break;
}
else
{
if (next_vec[current_vec] == -1)
{
unique = TRUE;
walk[i] = *pckd_vec;
next_vec[current_vec] = i;
next_vec[i] = -1;
break;
}
else
{
current_vec = next_vec[current_vec];
}
}
} /* for EVER */
} /* if (bit_sum_chain...) */
} /* while ((!unique... ))*/
/*
* If Unique is TRUE at this point, we have a unique
* vector stored, we have to set up old_bit sum and unpckd_vec
* for the next vector.
* If unique is FALSE, we have tried to create a unique vector
* MAX_RETRY times, and failed. We therefore signal an error.
*/
if (unique)
{
for (j = 0; j < width; j++)
{
unpckd_vec[j] = this_vec[j];
}
old_bit_sum = bit_sum;
}
else
{
(void) farfree(walk);
walk = NULL;
break;
}
} /* for */
/* Free space in memory */
(void) farfree(bit_sum_chain);
(void) farfree(next_vec);
(void) farfree(unpckd_vec);
(void) farfree(this_vec);
(void) farfree(mark_vec);
/* Return final vector */
return(walk);
}
/*****************************************************************************
**** ****
**** LPATREE atree_create(numvars,leaves) ****
**** ****
**** int numvars; ****
**** int leaves; ****
**** ****
**** Synopsis: ****
**** ****
**** Creates an Armstrong tree with _leaves_ number of leaves connected ****
**** to _numvars_ variables and their complements. The number of ****
**** leaves should probably be at least twice _numvars_. ****
**** The node functions and the connections are picked at random. ****
**** ****
*****************************************************************************/
public LPATREE FAR PASCAL
atree_create(numvars,leaves)
int numvars;
int leaves;
{
LPATREE tree;
LPINT connection;
BOOL far *complemented;
BOOL comp;
int i;
assert(leaves > 0);
assert(numvars > 0);
/*
* Create a list of bit inputs and shuffle, complemented inputs
* are marked with a TRUE in the complemented array.
*/
connection = (LPINT) farmalloc((unsigned) sizeof(int) * leaves);
MEMCHECK(connection);
complemented = (BOOL far *) farmalloc((unsigned) sizeof(BOOL) * leaves);
MEMCHECK(complemented);
comp = FALSE;
for (i = 0; i < leaves; i++)
{
int numvarscount = i % numvars;
if (numvarscount == 0)
{
comp = !comp;
}
connection[i] = numvarscount;
complemented[i] = comp;
}
/* Shuffle */
for (i = 0; i < leaves; i++)
{
int a;
int b;
int tmp;
a = RANDOM(leaves);
b = RANDOM(leaves);
tmp = connection[a];
connection[a] = connection[b];
connection[b] = tmp;
tmp = complemented[a];
complemented[a] = complemented[b];
complemented[b] = tmp;
}
tree = build_tree(connection, complemented, 0, leaves - 1);
(void) farfree(connection);
(void) farfree(complemented);
return(tree);
}
/*****************************************************************************
**** ****
**** void atree_free(tree) ****
**** ****
**** LPATREE tree; ****
**** ****
**** Synopsis: ****
**** ****
**** Returns memory occupied by _tree_ to the freelists. ****
*****************************************************************************/
public void FAR PASCAL
atree_free(tree)
LPATREE tree;
{
if (tree -> c_tag != LEAF)
{
atree_free(tree -> n_child_left);
atree_free(tree -> n_child_right);
}
reclaim_node(tree);
}
/*****************************************************************************
**** ****
**** (int) atree_eval(tree,vec) ****
**** ****
**** LPATREE tree; ****
**** LPBIT_VEC vec; ****
**** ****
**** Synopsis: ****
**** ****
**** Applies the _tree_ to the bit vector _vec_ and returns the result, ****
**** 1 for true, and 0 for false. ****
*****************************************************************************/
public BOOL FAR PASCAL
atree_eval(tree,vec)
LPATREE tree;
LPBIT_VEC vec;
{
register BOOL result;
switch (tree -> c_tag)
{
case AND:
tree -> n_sig_right = UNEVALUATED;
// turn off compiler possibly incorrect assignment warning
#pragma warn -pia
result = (tree -> n_sig_left =
atree_eval(tree -> n_child_left, vec))
&& (tree -> n_sig_right =
atree_eval(tree -> n_child_right, vec));
// restore warning state
#pragma warn .pia
break;
case RIGHT:
tree -> n_sig_left = UNEVALUATED;
result = (tree -> n_sig_right =
atree_eval(tree -> n_child_right, vec));
break;
case LEFT:
tree -> n_sig_right = UNEVALUATED;
result = (tree -> n_sig_left =
atree_eval(tree -> n_child_left, vec));
break;
case OR:
tree -> n_sig_right = UNEVALUATED;
// turn off compiler possibly incorrect assignment warning
#pragma warn -pia
result = (tree -> n_sig_left =
atree_eval(tree -> n_child_left, vec))
|| (tree -> n_sig_right =
atree_eval(tree -> n_child_right, vec));
// restore warning state
#pragma warn .pia
break;
case LEAF:
result = bv_extract((int) tree -> l_bit_no, vec) != tree -> l_comp;
break;
}
return(result);
}
/*****************************************************************************
**** ****
**** int atree_train(tree,tset,correct_result,bit_col,tset_size, ****
**** no_correct,epochs,verbosity) ****
**** ****
**** LPATREE tree; ****
**** LPBIT_VEC tset; ****
**** LPBIT_VEC correct_result; ****
**** int bit_col; ****
**** int tset_size; ****
**** int no_correct; ****
**** int epochs; ****
**** int verbosity; ****
**** ****
**** Synopsis: ****
**** ****
**** This routine is the heart of the library. It takes an atree _tree_ ****
**** to be trained, an array of input vectors _tset_, an array of ****
**** vectors, _correct_result_ where each bit column holds a correct bit ****
**** result for each vector in _tset_. [Note: Only a single vector is ****
**** actually required here, but doing it this way make life convenient ****
**** for training collections of trees for real numbers] An integer ****
**** _bit_col_ denoting the column to be trained on. Another integer ****
**** _test_size gives the size of both the _tset_ and _correct_result_ ****
**** arrays. ****
**** ****
**** The _tree_ is trained until the number of vectors presented in ****
**** _tset_ equals _epoch_ epochs, or the last presentation of the number****
**** in an epoch had at least _no_correct_ presentations. ****
**** The _verbosity_ is currently 0 or 1. ****
**** The routine returns TRUE if it stopped because it succeeded ****
**** _no_correct_ times. Returns FALSE if it did not achieve ****
**** _no_correct_. Returns -1 if aborted. ****
**** ****
*****************************************************************************/
#pragma argsused
public int FAR PASCAL
atree_train(tree,tset,correct_result,bit_col,tset_size,no_correct,
epochs,verbosity)
LPATREE tree;
LPBIT_VEC tset;
LPBIT_VEC correct_result;
int bit_col;
int tset_size;
int no_correct;
int epochs;
int verbosity;
{
BOOL no_correct_flag = FALSE;
LPINT vec_list;
int i;
int j;
int cor_this_epoch;
int vec_num;
LPBIT_VEC vec;
static BOOL show_status = TRUE;
// verbosity parm has no effect in Windows version
SetDlgItemText(hStatusWnd, IDD_ATREE_EPOCH, " ");
SetDlgItemText(hStatusWnd, IDD_ATREE_CORRECT, " ");
SetDlgItemText(hStatusWnd, IDD_ATREE_ACTUAL, " ");
if(show_status)
{
ShowWindow(hStatusWnd, SW_SHOWNOACTIVATE);
}
UpdateWindow(hStatusWnd);
vec_list = (LPINT) farmalloc((unsigned) sizeof(int) * tset_size);
MEMCHECK(vec_list);
for (i = 0; i < tset_size; i++)
{
vec_list[i] = i;
}
/* For the specified number of epochs */
for (i = 0; i < epochs; i++)
{
cor_this_epoch = 0;
SetDlgItemInt(hStatusWnd, IDD_ATREE_EPOCH, i, FALSE);
/* Shuffle */
for (j = 0; j < tset_size; j++)
{
int a;
int b;
int tmp;
a = RANDOM(tset_size);
do
{
b = RANDOM(tset_size);
}
while (a == b);
tmp = vec_list[a];
vec_list[a] = vec_list[b];
vec_list[b] = tmp;
}
/* For the elements of the test set */
for (j = 0; j < tset_size; j++)
{
if (atree_quit_flag)
{
atree_quit_flag = FALSE;
(void) farfree(vec_list);
show_status = ShowWindow(hStatusWnd, SW_HIDE);
return(-1); // exit if requested
}
/* Pick a random vector */
vec_num = vec_list[j];
vec = tset + vec_num;
/* Train the tree */
if (train(tree,vec,bv_extract(bit_col,correct_result + vec_num)))
{
/* The tree succeeded */
cor_this_epoch++;
if (cor_this_epoch == no_correct)
{
no_correct_flag = TRUE;
break; /* out of this epoch */
} /* if (cor_this...) */
} /* if (train..) */
} /* for (j = ..) */
SetDlgItemInt(hStatusWnd, IDD_ATREE_CORRECT, cor_this_epoch, FALSE);
/* If no_correct_flag is TRUE here, its time to stop */
if (no_correct_flag || i == epochs - 1)
{
int correct = 0;
for (j = 0; j < tset_size; j++)
{
if (atree_eval(tree, tset + j)
== bv_extract(bit_col, correct_result + j))
{
correct++;
}
}
SetDlgItemInt(hStatusWnd, IDD_ATREE_ACTUAL, correct, FALSE);
if (correct >= no_correct)
{
break; /* out of the epoch loop */
}
}
} /* for (i = ...) */
(void) farfree(vec_list);
show_status = ShowWindow(hStatusWnd, SW_HIDE);
return(no_correct_flag);
}
/*****************************************************************************
**** ****
**** (void) atree_print(tree,stream, verbosity) ****
**** ****
**** LPATREE tree; ****
**** FILE *stream; ****
**** int verbosity; ****
**** ****
**** Synopsis: ****
**** ****
**** Prints out a tree for diagnostic and explanation purposes, the ****
**** verbosity levels are 0 or above. ****
*****************************************************************************/
public void FAR PASCAL
atree_print(tree, stream, verbosity)
LPATREE tree;
FILE *stream;
int verbosity;
{
/*
* This routine makes an immediate call to the private
* print tree routine that takes an extra parameter
* controlling the indentation.
*/
print_tree(tree,stream,0,verbosity);
}
/*****************************************************************************
**** ****
**** LPATREE atree_fold(tree) ****
**** ****
**** LPATREE tree; ****
**** ****
**** Synopsis: ****
**** ****
**** This function removes all LEFT and RIGHT nodes from _tree_ ****
**** and returns a pointer to the resulting tree. ****
**** ****
*****************************************************************************/
public LPATREE FAR PASCAL
atree_fold(tree)
LPATREE tree;
{
LPATREE folded_tree;
int keep;
switch (tree -> c_tag)
{
case LEAF:
folded_tree = tree;
break;
case OR:
case AND:
tree -> n_child_left = atree_fold(tree -> n_child_left);
tree -> n_child_right = atree_fold(tree -> n_child_right);
folded_tree = tree;
break;
case LEFT:
case RIGHT:
keep = (tree -> c_tag == LEFT) ? LEFT_CHILD : RIGHT_CHILD;
folded_tree = atree_fold(tree -> n_child[keep]);
atree_free(tree -> n_child[!keep]);
reclaim_node(tree);
break;
default:
assert(0);
}
return(folded_tree);
}
/*****************************************************************************
**** ****
**** LPFAST_TREE atree_compress(tree) ****
**** ****
**** LPATREE tree; ****
**** ****
**** Synopsis: ****
**** ****
**** This function converts an atree to a fast_tree. ****
**** See the commentary for the private function ****
**** compress_tree for more information. ****
**** ****
*****************************************************************************/
public LPFAST_TREE FAR PASCAL
atree_compress(tree)
LPATREE tree;
{
LPFAST_TREE ftree;
int leaf_num;
int leaf_count = count_leaves(tree, TRUE);
ftree = (LPFAST_TREE) farmalloc((unsigned) (leaf_count + 1) * sizeof(fast_tree));
MEMCHECK(ftree);
ftree[leaf_count].bit_no = -1; /* mark end */
leaf_num = leaf_count - 1;
compress_tree(tree, NULL, NULL, ftree, &leaf_num);
return(ftree);
}
/*****************************************************************************
**** ****
**** BOOL atree_fast_eval(ftree, vec) ****
**** ****
**** LPFAST_TREE ftree; ****
**** LPBIT_VEC vec; ****
**** ****
**** Synopsis: ****
**** ****
**** This function is the fast_tree equivalent of atree_eval. ****
**** ****
*****************************************************************************/
public BOOL FAR PASCAL
atree_fast_eval(ftree, vec)
register LPFAST_TREE ftree;
LPBIT_VEC vec;
{
register int result;
do
{
result = bv_extract(ftree -> bit_no, vec) != ftree -> comp;
} while ((ftree = ftree -> next[result]) != NULL);
return(result);
}
/*****************************************************************************
**** ****
**** void atree_fast_print(ftree, stream) ****
**** ****
**** LPFAST_TREE ftree; ****
**** FILE *stream; ****
**** ****
**** Synopsis: ****
**** ****
**** This function is outputs the fast tree _ftree_ to stream. ****
**** ****
*****************************************************************************/
public void FAR PASCAL
atree_fast_print(ftree, stream)
LPFAST_TREE ftree;
FILE *stream;
{
int i;
for (i = 0; ftree[i].bit_no >= 0; i++)
{
fprintf(stream, "[%3d] bit=%s%d, next[0]=%d, next[1]=%d\n",
i, ftree[i].comp ? "!" : "", ftree[i].bit_no,
ftree[i].next[0] ? ftree[i].next[0] - ftree : -1,
ftree[i].next[1] ? ftree[i].next[1] - ftree : -1);
}
}
/*****************************************************************************
**** ****
**** int atree_set_code(code, low, high, count, width, dist) ****
**** ****
**** LPCODE_T code; ****
**** double low; ****
**** double high; ****
**** int count; ****
**** int width; ****
**** int dist; ****
**** ****
**** Synopsis: ****
**** ****
**** This is the constructor for type code_t: _code_ is a far pointer ****
**** to a code_t struct, _low_ and _high_ represent the real valued ****
**** boundaries of the encoding, _count_ represents the number of ****
**** vectors in the encoding, _width_ is the number of bits per vector, ****
**** and _dist_ is the number of bits to change between successive ****
**** vectors. ****
**** Returns non-zero on FAILURE. ****
**** ****
*****************************************************************************/
public int FAR PASCAL
atree_set_code(code, low, high, count, width, dist)
LPCODE_T code;
double low;
double high;
int count;
int width;
int dist;
{
int error = FALSE;
assert(low < high);
assert(count > 1);
assert(width > 0);
assert(dist > 0);
code -> width = width;
code -> low = low;
code -> high = high;
if (width == 1) /* boolean */
{
code -> vector = (LPBIT_VEC) farmalloc((unsigned) sizeof(bit_vec) * 2);
MEMCHECK(code -> vector);
// boolean 1
code -> vector[0] = *bv_create(1);
bv_set(0, &(code -> vector[0]), 0);
// boolean 0
code -> vector[1] = *bv_create(1);
bv_set(0, &(code -> vector[1]), 1);
code -> vector_count = 2;
code -> step = high - low;
}
else
{
if ((code -> vector = atree_rand_walk(count, width, dist)) == NULL)
{
error = TRUE;
}
code -> vector_count = count;
code -> step = (high - low) / (count - 1);
}
return(error);
}
/*****************************************************************************
**** ****
**** int atree_encode(x, code) ****
**** ****
**** double x; ****
**** LPCODE_T code; ****
**** ****
**** Synopsis: ****
**** ****
**** returns the quantization level corresponding to the floating point ****
**** value _x_. To get the bit vector, use the expression: ****
**** ****
**** code -> vector + atree_encode(x, code) ****
**** ****
*****************************************************************************/
public int FAR PASCAL
atree_encode(x, code)
double x;
LPCODE_T code;
{
int index;
if (code -> width == 1)
{
index = x > (code -> low + code -> high) / 2;
}
else if (x < code -> low)
{
// char szBuffer[100];
// (void) sprintf(szBuffer,
// "warning: atree_encode: argument out of range: %f\n", x);
// MessageBox(GetDesktopWindow(), szBuffer, "atree_encode()",
// MB_ICONHAND | MB_SYSTEMMODAL);
index = 0;
}
else if (x > code -> high)
{
// char szBuffer[100];
// (void) sprintf(szBuffer,
// "warning: atree_encode: argument out of range: %f\n", x);
// MessageBox(GetDesktopWindow(), szBuffer, "atree_encode()",
// MB_ICONHAND | MB_SYSTEMMODAL);
index = code -> vector_count - 1;
}
else
{
index = (int) floor(((x - code -> low) / code -> step) + 0.5);
}
return(index);
}
/*****************************************************************************
**** ****
**** int atree_decode(vec, code) ****
**** ****
**** LPBIT_VEC vec; ****
**** LPCODE_T code; ****
**** ****
**** Synopsis: ****
**** ****
**** returns the quantization level corresponding to the bit vector ****
**** _vec_. To get the corresponding floating point value, use the ****
**** expression: ****
**** ****
**** code -> low + code -> step * atree_decode(vec, code) ****
**** ****
*****************************************************************************/
public int FAR PASCAL
atree_decode(vec, code)
LPBIT_VEC vec;
LPCODE_T code;
{
int closest = 0;
if (code -> width == 1) /* boolean */
{
closest = bv_extract(0, vec);
}
else
{
int i;
int diff;
int closest_bit_diff = code -> width;
for (i = 0; i < code -> vector_count; i++)
{
if ((diff = bv_diff(vec, code -> vector + i)) < closest_bit_diff)
{
closest_bit_diff = diff;
closest = i;
}
}
}
return(closest);
}
/*
* atree I/O routines.
*/
/*****************************************************************************
**** ****
**** int atree_tree(tree, filename) ****
**** ****
**** LPATREE tree; ****
**** LPSTR filename; ****
**** ****
**** Synopsis: ****
**** ****
**** Creates a file "filename", and stores the single tree pointed ****
**** to by _tree_ in that file. ****
**** Returns non-zero on failure. ****
**** ****
*****************************************************************************/
public int FAR PASCAL
atree_store(tree, filename)
LPATREE tree;
LPSTR filename;
{
FILE *fp;
char szName[80];
lstrcpy(szName, filename); // fopen doesn't take LPSTR
if ((fp = fopen(szName, "w")) == NULL)
{
return(errno);
}
atree_write(fp, tree);
fclose(fp);
return(0);
}
/*****************************************************************************
**** ****
**** LPATREE atree_load(filename) ****
**** ****
**** LPSTR filename; ****
**** ****
**** Synopsis: ****
**** ****
**** Reads from file "filename", and returns the first tree contained ****
**** in that file. ****
**** ****
*****************************************************************************/
public LPATREE FAR PASCAL
atree_load(filename)
LPSTR filename;
{
FILE *fp;
LPATREE tree;
char szName[80];
lstrcpy(szName, filename); // fopen doesn't take LPSTR
if ((fp = fopen(szName, "r")) == NULL)
{
return(NULL);
}
tree = atree_read(fp);
fclose(fp);
return(tree);
}
/*****************************************************************************
**** ****
**** int atree_write(tree, stream) ****
**** ****
**** LPATREE tree; ****
**** FILE *stream; ****
**** ****
**** Synopsis: ****
**** ****
**** Stores a single _tree_ onto _stream_. ****
**** Returns 0 for success, 1 on failure. ****
**** ****
*****************************************************************************/
public int FAR PASCAL
atree_write(stream, tree)
FILE *stream;
LPATREE tree;
{
return store_tree(tree, stream) || fprintf(stream, ";\n") == EOF;
}
/*****************************************************************************
**** ****
**** LPATREE atree_read(stream) ****
**** ****
**** FILE *stream; ****
**** ****
**** Synopsis: ****
**** ****
**** Reads tree stored in postfix notation. Valid symbols are: ****
**** '&', '|', 'L', 'R' (AND, OR, LEFT, and RIGHT respectively), ****
**** and numerals (representing bit numbers) optionally preceded ****
**** by a '!' for negation. Returns NULL if any error or EOF is ****
**** encountered. A file may store multiple trees, each tree is ****
**** separated by a ';'. ****
**** ****
*****************************************************************************/
public LPATREE FAR PASCAL
atree_read(stream)
FILE *stream;
{
token_t t;
LPATREE node = NULL;
int error = 0;
LPATREE stack[STACKSIZE];
int top = 0;
#define ITEMS top
#define PUSH(node) stack[top++] = (node)
#define POP stack[--top]
while ((error = get_token(stream, &t)) == 0)
{
if (t.token == EOF || t.token == ';')
{
break;
}
if (t.token == LEAF_TOKEN)
{
node = get_node(LEAF);
node -> l_bit_no = t.bit_no;
node -> l_comp = t.complemented;
}
else if (ITEMS < 2)
{
char szBuffer[80];
(void) sprintf(szBuffer,
"atree_read: too few arguments for %c, offset %ld\n",
t.token, ftell(stream));
MessageBox(GetDesktopWindow(), szBuffer, "atree_read()",
MB_ICONHAND | MB_SYSTEMMODAL);
error++;
break;
}
else
{
node = get_node(!LEAF);
node -> n_cnt_left = (t.token == '|' || t.token == 'L')
? MAXSET : MINSET;
node -> n_cnt_right = (t.token == '|' || t.token == 'R')
? MAXSET : MINSET;
node -> c_tag = node_function(node);
node -> n_sig_left = UNEVALUATED;
node -> n_sig_right = UNEVALUATED;
node -> n_child_right = POP;
node -> n_child_left = POP;
}
if (ITEMS >= STACKSIZE)
{
char szBuffer[80];
(void) sprintf(szBuffer, "atree_read: stack overflow\n");
MessageBox(GetDesktopWindow(), szBuffer, "atree_read()",
MB_ICONHAND | MB_SYSTEMMODAL);
error++;
break;
}
else
{
PUSH(node);
}
} /* while */
if (!error && ITEMS != 1)
{
char szBuffer[80];
(void) sprintf(szBuffer, "atree_read: unexpected ");
if (t.token == EOF)
{
strcat(szBuffer, "EOF\n");
}
else
{
char szErr[80];
(void) sprintf(szErr, "';', offset %ld\n", ftell(stream));
strcat(szBuffer, szErr);
}
MessageBox(GetDesktopWindow(), szBuffer, "atree_read()",
MB_ICONHAND | MB_SYSTEMMODAL);
error++;
}
return(error ? NULL : node);
#undef ITEMS
#undef PUSH
#undef POP
}
/*
* code I/O routines
*/
/*****************************************************************************
**** ****
**** int atree_write_code(stream, code) ****
**** ****
**** FILE *stream; ****
**** LPCODE_T code; ****
**** ****
**** Synopsis: ****
**** ****
**** Writes _code_ onto _stream_. ****
**** Returns 0 for success, 1 on failure. ****
**** ****
*****************************************************************************/
public int FAR PASCAL
atree_write_code(stream, code)
FILE *stream;
LPCODE_T code;
{
int i;
int error;
error = fprintf(stream, CODING_HEADER_FORMAT,
code -> vector_count, code -> width,
code -> low, code -> high) == EOF;
if (!error && code -> width > 1)
{
for (i = 0; i < code -> vector_count; i++)
{
if (bv_print(stream, code -> vector + i)
|| fprintf(stream, "\n") == EOF)
{
error = TRUE;
break;
}
}
}
return(error);
}
/*****************************************************************************
**** ****
**** LPCODE_T atree_read_code(stream) ****
**** ****
**** FILE *stream; ****
**** LPCODE_T code; ****
**** ****
**** Synopsis: ****
**** ****
**** Reads a _code_ from _stream_. ****
**** Returns NULL if unsuccessful, returns _code_ if successful. ****
**** ****
*****************************************************************************/
public LPCODE_T FAR PASCAL
atree_read_code(stream, code)
FILE *stream;
LPCODE_T code;
{
char *buf;
char *p;
int i;
int error = 0;
int count, width;
float high, low;
if (fscanf(stream, CODING_HEADER_FORMAT,
&count, &width, &low, &high) != CODING_HEADER_ITEMS)
{
char szBuffer[80];
(void) sprintf(szBuffer, "atree_read_code: bad header, offset %ld\n",
ftell(stream));
MessageBox(GetDesktopWindow(), szBuffer, "atree_read_code()",
MB_ICONHAND | MB_SYSTEMMODAL);
return(NULL);
}
else if (count < 2)
{
char szBuffer[80];
(void) sprintf(szBuffer,
"atree_read_code: vector count too low, offset %ld\n",
ftell(stream));
MessageBox(GetDesktopWindow(), szBuffer, "atree_read_code()",
MB_ICONHAND | MB_SYSTEMMODAL);
return(NULL);
}
else if (high <= low)
{
char szBuffer[80];
(void) sprintf(szBuffer,
"atree_read_code: bad range, offset %ld\n",
ftell(stream));
MessageBox(GetDesktopWindow(), szBuffer, "atree_read_code()",
MB_ICONHAND | MB_SYSTEMMODAL);
return(NULL);
}
else if (width < 1)
{
char szBuffer[80];
(void) sprintf(szBuffer,
"atree_read_code: width must be at least 1, offset %ld\n",
ftell(stream));
MessageBox(GetDesktopWindow(), szBuffer, "atree_read_code()",
MB_ICONHAND | MB_SYSTEMMODAL);
return(NULL);
}
code -> vector_count = count;
code -> width = width;
code -> low = low;
code -> high = high;
if (width == 1)
{
atree_set_code(code, code -> low, /* low */
code -> high, /* high */
2, /* count */
1, /* width */
1); /* distance */
}
else {
code -> step = (code->high - code->low ) / (code -> vector_count - 1);
code -> vector = (LPBIT_VEC)
farmalloc((unsigned) sizeof(bit_vec) * code -> vector_count);
MEMCHECK(code -> vector);
buf = malloc((unsigned) code -> width + 2); /* room for \n and \0 */
MEMCHECK(buf);
for (i = 0; i < code -> vector_count; i++)
{
if (fgets(buf, code -> width + 2, stream) == NULL)
{
char szBuffer[80];
(void) sprintf(szBuffer,
"atree_read_code: read error on offset %ld\n",
ftell(stream));
MessageBox(GetDesktopWindow(), szBuffer, "atree_read_code()",
MB_ICONHAND | MB_SYSTEMMODAL);
error++;
break;
}
if (strlen(buf) != code -> width + 1
|| buf[code -> width] != '\n')
{
char szBuffer[80];
(void) sprintf(szBuffer,
"atree_read_code: inconsistent vector length, offset %ld\n",
ftell(stream));
MessageBox(GetDesktopWindow(), szBuffer, "atree_read_code()",
MB_ICONHAND | MB_SYSTEMMODAL);
error++;
break;
}
else
{
buf[code -> width] = '\0'; /* remove \n */
}
if (strspn(buf, "01") != code -> width)
{
char szBuffer[80];
(void) sprintf(szBuffer,
"atree_read_code: garbage at offset %ld\n",
ftell(stream));
MessageBox(GetDesktopWindow(), szBuffer, "atree_read_code()",
MB_ICONHAND | MB_SYSTEMMODAL);
error++;
break;
}
/*
* prepare the vector for packing
*/
for (p = buf; *p; p++)
{
*p -= '0';
}
code -> vector[i] = *(bv_pack(buf, code -> width));
}
(void) farfree(buf);
if (error)
{
(void) farfree(code -> vector);
code = NULL;
}
}
return(code);
}
/*****************************************************************************
*****************************************************************************
**** ****
**** Private Routines ****
**** ****
*****************************************************************************
*****************************************************************************/
/*
* Free list management routines.
*/
static LPATREE_LEAF free_leaf_list = NULL;
static LPATREE_NODE free_node_list = NULL;
#define get_free_list(type, free_list) { \
int i; \
type far *ptr = (type far *) farmalloc(sizeof(type) * NEWMALLOC); \
MEMCHECK(ptr); \
for (i = 0; i < NEWMALLOC - 1; i++) \
ptr[i].next = &ptr[i + 1]; \
ptr[NEWMALLOC - 1].next = free_list; \
free_list = ptr; \
}
private LPATREE NEAR PASCAL
get_node(tag)
int tag;
{
LPATREE node;
if (tag == LEAF)
{
/*
* add to free_leaf_list if necessary.
*/
if (free_leaf_list == NULL)
{
get_free_list(atree_leaf, free_leaf_list);
}
node = (LPATREE) free_leaf_list;
free_leaf_list = free_leaf_list -> next;
}
else {
/*
* add to free_node_list if necessary.
*/
if (free_node_list == NULL)
{
get_free_list(atree_node, free_node_list);
}
node = (LPATREE) free_node_list;
free_node_list = free_node_list -> next;
}
node -> c_tag = tag;
return(node);
}
#undef get_free_list
/*
* function reclaim_node()
*
* returns a node to its appropriate free_list
*/
private void NEAR PASCAL
reclaim_node(tree)
LPATREE tree;
{
if (tree -> c_tag == LEAF)
{
tree -> leaf.next = free_leaf_list;
free_leaf_list = (LPATREE_LEAF) tree;
}
else
{
tree -> node.next = free_node_list;
free_node_list = (LPATREE_NODE) tree;
}
}
/*
* This routine recursively creates a random tree in the previously allocated
* space starting at _tree_. It returns a pointer giving the next available
* space for other calls.
*/
private LPATREE NEAR PASCAL
build_tree(connection, complemented, start, end)
LPINT connection;
BOOL far *complemented;
int start;
int end;
{
LPATREE node;
int mid;
/* Are we at a leaf? */
if (start == end)
{
node = get_node(LEAF);
node -> l_comp = complemented[start];
node -> l_bit_no = connection[start];
}
else
{
/* This is a node. */
node = get_node(AND);
node -> c_tag = RANDOM(4);
node -> n_cnt_left =
(node -> c_tag == LEFT || node -> c_tag == OR) ? ABOVEMID : BELOWMID;
node -> n_cnt_right =
(node -> c_tag == RIGHT || node -> c_tag == OR) ? ABOVEMID : BELOWMID;
/* clear the signals */
node -> n_sig_right = UNEVALUATED;
node -> n_sig_left = UNEVALUATED;
/* Create descendants */
mid = start + ((end - start)/2);
node -> n_child_left
= build_tree(connection, complemented, start, mid);
node -> n_child_right
= build_tree(connection, complemented, mid+1, end);
}
return(node);
}
/*
* print_tree routine prints out an atree to the
* file pointed to by _stream_
*/
private void NEAR PASCAL
print_tree(tree, stream, indent,verbosity)
LPATREE tree;
FILE *stream;
int indent;
int verbosity;
{
int i;
if (tree -> c_tag != LEAF)
{
print_tree(tree -> n_child_right, stream, indent + 3, verbosity);
}
for (i = 0; i < indent; i++)
{
fprintf(stream, " ");
}
switch (tree -> c_tag)
{
case AND:
fprintf(stream, "AND\n");
break;
case LEFT:
fprintf(stream, "LEFT\n");
break;
case RIGHT:
fprintf(stream, "RIGHT\n");
break;
case OR:
fprintf(stream, "OR\n");
break;
case LEAF:
fprintf(stream, "%sLEAF : %d\n",
tree -> l_comp ? "~" : "", tree -> l_bit_no);
break;
}
if (tree -> c_tag != LEAF)
{
print_tree(tree -> n_child_left, stream, indent + 3, verbosity);
}
}
/*
* This routine is actually responsible for the training of a tree for a
* single input vector and desired result. If the tree gets the correct result
* before the adaptation step occurs, the routine returns TRUE, otherwise,
* false.
*/
private BOOL NEAR PASCAL
train(tree,vec,desired)
LPATREE tree;
LPBIT_VEC vec;
BOOL desired;
{
BOOL correct;
(void) atree_eval(tree,vec);
adapt(tree,vec,desired);
correct = atree_eval(tree,vec) == desired;
if (!correct)
{
adapt(tree,vec,desired);
}
return(correct);
}
private void NEAR PASCAL
adapt(tree,vec,desired)
LPATREE tree;
LPBIT_VEC vec;
BOOL desired;
{
register int lres;
register int rres;
register int funct;
/*
* INCR and DECR implement bounded counters.
*/
#define INCR(t) ((t) += ((t) < MAXSET))
#define DECR(t) ((t) -= ((t) > MINSET))
Windows_Interrupt(200);
funct = tree -> c_tag;
if (funct != LEAF)
{
/* If the left child is unevaluated, evaluate it */
if ((lres = tree -> n_sig_left) == UNEVALUATED)
{
lres = atree_eval(tree -> n_child_left, vec);
tree -> n_sig_left = lres;
}
/* If the right child is unevaluated, evaluate it */
if ((rres = tree -> n_sig_right) == UNEVALUATED)
{
rres = atree_eval(tree -> n_child_right, vec);
tree -> n_sig_right = rres;
}
/* Update the counters if needed */
if (lres != rres)
{
if (lres)
{
(void) (desired ? INCR(tree -> n_cnt_left)
: DECR(tree -> n_cnt_left));
}
else
{
(void) (desired ? INCR(tree -> n_cnt_right)
: DECR(tree -> n_cnt_right));
}
/* has the node function changed? */
tree -> c_tag = node_function(tree);
funct = tree -> c_tag;
}
/* Assign responsibility to the left child */
if (rres != desired || funct != (rres ? OR : AND))
{
adapt(tree -> n_child_left, vec, desired);
}
/* Assign responsibility to the right child */
if (lres != desired || funct != (lres ? OR : AND))
{
adapt(tree -> n_child_right, vec, desired);
}
}
#undef INCR
#undef DECR
}
private int NEAR PASCAL
node_function(tree)
LPATREE tree;
{
int result;
if ((tree -> n_cnt_left) >= ABOVEMID)
{
result = (tree -> n_cnt_right >= ABOVEMID) ? OR : LEFT;
}
else
{
result = (tree -> n_cnt_right >= ABOVEMID) ? RIGHT : AND;
}
return(result);
}
/*
* compress_tree:
* Alters the respresentation of an atree into a fast_tree.
* A fast_tree is essentially a list of leaves; each leaf in the
* list contains two pointers to subsequent leaves to evaluate,
* one for each possible result of evaluating the current leaf.
* A next pointer of NULL indicates that the evaluation is complete,
* and the result of the tree is the result of the current leaf.
*
* parameters:
* 'next_if_0' and 'next_if_1' each hold the location of the
* next leaf to evaluate if the value of the current 'node' is
* known. Of course, for the root these are NULL. 'leaf_num' is the
* current index into 'ftree'; it starts at the last leaf.
*
* notes:
* For non-leaf nodes, we traverse the children in reverse order
* because we need to know the first leaf of a node's sibling (this
* is the next leaf to evaluate if any children of 'node' produce a
* tag value). If we go backwards, we know that this is the last
* leaf we visited.
*/
private void NEAR PASCAL
compress_tree(node, next_if_0, next_if_1, ftree, leaf_num)
LPATREE node;
LPFAST_TREE next_if_0;
LPFAST_TREE next_if_1;
LPFAST_TREE ftree;
LPINT leaf_num;
{
assert(*leaf_num >= 0);
switch (node -> c_tag)
{
case LEAF:
ftree[*leaf_num].next[0] = next_if_0;
ftree[*leaf_num].next[1] = next_if_1;
ftree[*leaf_num].bit_no = node -> l_bit_no;
ftree[*leaf_num].comp = node -> l_comp;
(*leaf_num)--;
break;
case AND:
compress_tree(node->n_child[1], next_if_0, next_if_1, ftree, leaf_num);
compress_tree(node->n_child[0], next_if_0, &ftree[*leaf_num+1], ftree,
leaf_num);
break;
case OR:
compress_tree(node->n_child[1], next_if_0, next_if_1, ftree, leaf_num);
compress_tree(node->n_child[0], &ftree[*leaf_num+1], next_if_1, ftree,
leaf_num);
break;
case LEFT:
compress_tree(node->n_child[0], next_if_0, next_if_1, ftree, leaf_num);
break;
case RIGHT:
compress_tree(node->n_child[1], next_if_0, next_if_1, ftree, leaf_num);
break;
default:
assert(0);
}
}
private int NEAR PASCAL
count_leaves(tree, fold)
LPATREE tree;
int fold;
{
if (tree -> c_tag == LEAF)
{
return 1;
}
else if (fold && tree -> c_tag == LEFT)
{
return count_leaves(tree -> n_child_left, fold);
}
else if (fold && tree -> c_tag == RIGHT)
{
return count_leaves(tree -> n_child_right, fold);
}
else
{
return count_leaves(tree -> n_child_left, fold)
+ count_leaves(tree -> n_child_right, fold);
}
}
/*
* function: store_tree
*
* Stores _tree_ onto _stream_ using postfix notation.
* Returns non-zero on failure.
*/
private int NEAR PASCAL
store_tree(tree, stream)
LPATREE tree;
FILE *stream;
{
int error;
if (tree -> c_tag == LEAF)
{
error = fprintf(stream, "%s%d ",
tree -> l_comp ? "!" : "", tree -> l_bit_no) == EOF;
}
else
{
error = store_tree(tree -> n_child_left, stream)
|| store_tree(tree -> n_child_right, stream);
if (!error)
{
switch (tree -> c_tag)
{
case AND:
error = fprintf(stream, "&") == EOF;
break;
case OR:
error = fprintf(stream, "|") == EOF;
break;
case LEFT:
error = fprintf(stream, "L") == EOF;
break;
case RIGHT:
error = fprintf(stream, "R") == EOF;
break;
}
}
}
return(error);
}
/*
* function: get_token
*
* Reads the next token from _stream_ and returns information about it
* in _t_. Returns 0 for success, 1 for failure.
*/
private int NEAR PASCAL
get_token(stream, t)
FILE *stream;
token_t far *t;
{
int c;
/* skip white space */
while (isspace(c = getc(stream)))
;
t -> complemented = 0;
switch (c)
{
case EOF:
case 'L':
case 'R':
case '&':
case '|':
case ';':
t -> token = c;
break;
case '!':
t -> complemented = 1;
/* skip white space */
while (isspace(c = getc(stream)))
;
if (!isdigit(c))
{
char szBuffer[80];
(void) sprintf(szBuffer,
"get_token: expecting digit after '!', offset %ld\n",
ftell(stream));
MessageBox(GetDesktopWindow(), szBuffer, "get_token()",
MB_ICONHAND | MB_SYSTEMMODAL);
return(1);
}
/* FALLTHRU */
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
t -> token = LEAF_TOKEN;
t -> bit_no = c - '0';
while (isdigit(c = getc(stream)))
{
t -> bit_no = t -> bit_no * 10 + c - '0';
}
(void) ungetc(c, stream);
break;
default:
{
char szBuffer[80];
(void) sprintf(szBuffer,
"get_token: unexpected symbol: '%c', offset %ld\n",
c, ftell(stream));
MessageBox(GetDesktopWindow(), szBuffer, "get_token()",
MB_ICONHAND | MB_SYSTEMMODAL);
return(1);
}
}
return(0);
}